package jogo;

import java.util.ArrayList;
import java.util.List;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import Cartas.Baralho;
import Cartas.Carta;
import Cartas.CartaNumerica;
import Cartas.ComprarDuas;
import Cartas.ComprarQuatro;
import Cartas.Cor;
import Cartas.Coringa;
import Cartas.Inverter;
import Cartas.Pular;

public class JogoTeste {

	@Before
	public void setUp() {
		//System.out.println(">>>>>>>>>>BEFORE");
		List<Jogador> jogs = new ArrayList<>();
		jogs.add(new Jogador());
		jogs.add(new Jogador());
		jogs.add(new Jogador());
		jogs.add(new Jogador());
		
		Jogo jogo = new Jogo(jogs);
	}
	
	@Test
	public void testeConstrutor(){
		
		List<Jogador> jogs = new ArrayList<>();
		jogs.add(new Jogador());
		jogs.add(new Jogador());
		jogs.add(new Jogador());
		jogs.add(new Jogador());
		
		Jogo jogo = new Jogo(jogs);
		
		//jogo.distribuirCartas();
		
		for (Jogador j : jogs) {
			Assert.assertEquals(7, j.getBaralho().getCartas().size());
		}
		
		//deve ser a quantidade de jogadore no jogo
		Assert.assertEquals(4, jogo.jogadores.size());
		
		Assert.assertNotNull(jogo.jogadorAtual);
		
		//quantidade de todas as cartas do baralho inicial menos a inicial, menos as cartas distribuidas entre os jogadores;
		Assert.assertEquals(108 - 1 - (7 * jogo.jogadores.size()), jogo.monteDisponivel.getCartas().size());
		Assert.assertEquals(0, jogo.monteJogado.getCartas().size());
		
		//deve ser uma carta diferente de nulo
		Assert.assertNotNull(jogo.cartaAmostra);
		
		Assert.assertNull(jogo.cartaJogadaAnterior);
		Assert.assertNull(jogo.vencedor);
		
	}
	
	@Test
	public void testeCartaInicial() {
		
		Pular cPula = new Pular(Cor.AMARELO);
		CartaNumerica cNumerica = new CartaNumerica(Cor.AZUL, 7);
		Coringa coringa = new Coringa();
		ComprarQuatro c4 = new ComprarQuatro();
		ComprarDuas c2 = new ComprarDuas(Cor.VERDE);
		Inverter cInverte = new Inverter(Cor.VERMELHO);
		
		Baralho b = new Baralho(Baralho.VAZIO);
		b.adicionaCarta(cPula);
		b.adicionaCarta(cNumerica);
		b.adicionaCarta(c4);
		b.adicionaCarta(c2);
		b.adicionaCarta(cInverte);
		
		
		List jogadores = new ArrayList<Jogador>();
		jogadores.add(new Jogador());
		Jogo jogo  = new Jogo(jogadores);

		jogo.monteDisponivel = b;
		
		Carta cInicial = jogo.cartaInicial();
		Assert.assertEquals(cPula, cInicial);
		Assert.assertEquals(4, jogo.monteDisponivel.getCartas().size());
		Assert.assertFalse(jogo.monteDisponivel.possui(cInicial));
		
		
		
		b = new Baralho(Baralho.VAZIO);
		b.adicionaCarta(coringa);
		b.adicionaCarta(c4);
		b.adicionaCarta(cNumerica);
		b.adicionaCarta(cPula);
		b.adicionaCarta(c2);
		b.adicionaCarta(cInverte);
		
		jogo.monteDisponivel = b;
		
		cInicial = jogo.cartaInicial();
		Assert.assertNotEquals(coringa, cInicial);
		Assert.assertEquals(cNumerica, cInicial);
		Assert.assertEquals(5, jogo.monteDisponivel.getCartas().size());
		Assert.assertFalse(jogo.monteDisponivel.possui(cInicial));

		
		
		b = new Baralho(Baralho.VAZIO);
		b.adicionaCarta(c4);
		b.adicionaCarta(c2);
		b.adicionaCarta(coringa);
		b.adicionaCarta(cPula);
		b.adicionaCarta(cNumerica);
		b.adicionaCarta(cInverte);
		
		jogo.monteDisponivel = b;
		
		cInicial = jogo.cartaInicial();
		Assert.assertNotEquals(c4, cInicial);
		Assert.assertEquals(c2, cInicial);
		Assert.assertEquals(5, jogo.monteDisponivel.getCartas().size());
		Assert.assertFalse(jogo.monteDisponivel.possui(cInicial));

	}
	
	@Test
	public void testeProximoJogador() {
		
		Jogador j1 = new Jogador(1);
		Jogador j2 = new Jogador(2);
		Jogador j3 = new Jogador(3);
		Jogador j4 = new Jogador(4);
		
		List<Jogador> jogadores = new ArrayList<>();
		jogadores.add(j1);
		jogadores.add(j2);
		jogadores.add(j3);
		jogadores.add(j4);
		
		Jogo j = new Jogo(jogadores);
		
		j.jogadorAtual = j1;
		j.indiceJogadorAtual = 0;
		
		Assert.assertEquals(j1, j.jogadorAtual);
		Assert.assertEquals(j2, j.proximoJogador());
		Assert.assertEquals(j1, j.jogadorAnterior);
		Assert.assertEquals(j3, j.proximoJogador());
		Assert.assertEquals(j2, j.jogadorAnterior);
		Assert.assertEquals(j4, j.proximoJogador());
		Assert.assertEquals(j3, j.jogadorAnterior);
		Assert.assertEquals(j1, j.proximoJogador());
		Assert.assertEquals(j4, j.jogadorAnterior);
		
		//invertendo o sentido
		j.sentido = -1;
		Assert.assertEquals(j1, j.jogadorAtual);
		Assert.assertEquals(j4, j.proximoJogador());
		Assert.assertEquals(j1, j.jogadorAnterior);
		Assert.assertEquals(j3, j.proximoJogador());
		Assert.assertEquals(j4, j.jogadorAnterior);
		Assert.assertEquals(j2, j.proximoJogador());
		Assert.assertEquals(j3, j.jogadorAnterior);
		Assert.assertEquals(j1, j.proximoJogador());
		Assert.assertEquals(j2, j.jogadorAnterior);
	}
	

	@Test
	public void testeDesfazerProximo() {
		
		Jogador j1 = new Jogador(1);
		Jogador j2 = new Jogador(2);
		Jogador j3 = new Jogador(3);
		Jogador j4 = new Jogador(4);
		
		List<Jogador> jogadores = new ArrayList<>();
		jogadores.add(j1);
		jogadores.add(j2);
		jogadores.add(j3);
		jogadores.add(j4);
		
		Jogo j = new Jogo(jogadores);
		
		j.jogadorAtual = j1;
		j.indiceJogadorAtual = 0;
		
		Assert.assertEquals(j1, j.jogadorAtual);
		Assert.assertEquals(j2, j.proximoJogador());
		
		j.desfazerProximoJogador();
		Assert.assertEquals(j1, j.jogadorAtual);
		Assert.assertEquals(j4, j.jogadorAnterior);
		
		j.desfazerProximoJogador();
		Assert.assertEquals(j4, j.jogadorAtual);
		Assert.assertEquals(j3, j.jogadorAnterior);
		
		j.desfazerProximoJogador();
		Assert.assertEquals(j3, j.jogadorAtual);
		Assert.assertEquals(j2, j.jogadorAnterior);
		
		j.desfazerProximoJogador();
		Assert.assertEquals(j2, j.jogadorAtual);
		Assert.assertEquals(j1, j.jogadorAnterior);
		
		j.desfazerProximoJogador();
		Assert.assertEquals(j1, j.jogadorAtual);
		Assert.assertEquals(j4, j.jogadorAnterior);
		
		//invertendo o sentido
		j.sentido = -1;
		Assert.assertEquals(j4, j.proximoJogador());
		Assert.assertEquals(j1, j.jogadorAnterior);
		
		j.desfazerProximoJogador();
		Assert.assertEquals(j1, j.jogadorAtual);
		Assert.assertEquals(j2, j.jogadorAnterior);
		
		j.desfazerProximoJogador();
		Assert.assertEquals(j2, j.jogadorAtual);
		Assert.assertEquals(j3, j.jogadorAnterior);
		
		j.desfazerProximoJogador();
		Assert.assertEquals(j3, j.jogadorAtual);
		Assert.assertEquals(j4, j.jogadorAnterior);
		
		j.desfazerProximoJogador();
		Assert.assertEquals(j4, j.jogadorAtual);
		Assert.assertEquals(j1, j.jogadorAnterior);
	}
	
	
	/* 
	 * uma jogada eh dita ilegal quando o jogador joga o ComprarQuatro, tendo no seu baralho
	 * carta empilhável diferente dela.
	 */
	
	@Test
	public void testeJogadaIlega() {
		
		Jogador j1 = new Jogador(1);
		Jogador j2 = new Jogador(2);
		Jogador j3 = new Jogador(3);
		Jogador j4 = new Jogador(4);
		
		List<Jogador> jogadores = new ArrayList<>();
		jogadores.add(j1);
		jogadores.add(j2);
		jogadores.add(j3);
		jogadores.add(j4);
		
		Jogo j = new Jogo(jogadores);
		
		j.proximoJogador();
		
		j.cartaAmostra = new ComprarQuatro();
		
		//para controlar as cartas do jogador, removemos todas as cartas dele
		while (j.jogadorAnterior.getBaralho().retirarCarta() != null) {}
		
		//adicionamos as cartas q quisermos
		j.jogadorAnterior.getBaralho().adicionaCarta(new Inverter(Cor.AZUL));
		j.jogadorAnterior.getBaralho().adicionaCarta(new ComprarDuas(Cor.VERDE));
		j.jogadorAnterior.getBaralho().adicionaCarta(new ComprarDuas(Cor.VERDE));
		j.jogadorAnterior.getBaralho().adicionaCarta(new CartaNumerica(Cor.AMARELO, 3));
		
		j.cartaJogadaAnterior = new CartaNumerica(Cor.AZUL, 3);
		Assert.assertTrue(j.jogadaIlegal(j.jogadorAnterior));

		j.cartaJogadaAnterior = new CartaNumerica(Cor.VERMELHO, 5);
		Assert.assertFalse(j.jogadaIlegal(j.jogadorAnterior));
		
		j.cartaJogadaAnterior = new CartaNumerica(Cor.AMARELO, 8);
		Assert.assertTrue(j.jogadaIlegal(j.jogadorAnterior));
		
		j.cartaJogadaAnterior = new CartaNumerica(Cor.VERDE, 7);
		Assert.assertTrue(j.jogadaIlegal(j.jogadorAnterior));
		
		j.cartaJogadaAnterior = new Pular(Cor.AMARELO);
		Assert.assertTrue(j.jogadaIlegal(j.jogadorAnterior));
		
		//se ele tiver uma outra carta Comprar4, e não tiver qualquer outrar não empilhável,
		//sua jogada é legal
		j.jogadorAnterior.getBaralho().adicionaCarta(new ComprarQuatro());
		j.cartaJogadaAnterior = new Pular(Cor.VERMELHO);
		Assert.assertFalse(j.jogadaIlegal(j.jogadorAnterior));
		
		j.cartaJogadaAnterior = new Coringa();
		j.cartaJogadaAnterior.setCor(Cor.VERMELHO);
		Assert.assertFalse(j.jogadaIlegal(j.jogadorAnterior));
		
		//se ele tem uma carta coringa simples no seu baralho, sua jogada vai ser ilegal 
		//qualquer q seja a carta anterior
		j.jogadorAnterior.getBaralho().adicionaCarta(new Coringa());
		
		j.cartaJogadaAnterior = new CartaNumerica(Cor.VERDE, 4);
		Assert.assertTrue(j.jogadaIlegal(j.jogadorAnterior));
		j.cartaJogadaAnterior = new CartaNumerica(Cor.VERMELHO, 5);
		Assert.assertTrue(j.jogadaIlegal(j.jogadorAnterior));
		j.cartaJogadaAnterior = new CartaNumerica(Cor.AZUL, 6);
		Assert.assertTrue(j.jogadaIlegal(j.jogadorAnterior));
		j.cartaJogadaAnterior = new Inverter(Cor.AMARELO);
		Assert.assertTrue(j.jogadaIlegal(j.jogadorAnterior));
		
	}
	

	
	public List<Carta> monteDisponivelPadraoTeste() {
		Pular cd0 = new Pular(Cor.AZUL);
		Inverter cd1 = new Inverter(Cor.VERMELHO);
		List<Carta> monte = new ArrayList<>();
		monte.add(cd0);
		monte.add(cd1);
		
		return monte;
	}
	
	
	@Test
	public void testePegarCartasMonteDisponivel() {
		
		Jogador j1 = new Jogador(1);
		Jogador j2 = new Jogador(2);
		Jogador j3 = new Jogador(3);
		Jogador j4 = new Jogador(4);
		
		List<Jogador> jogadores = new ArrayList<>();
		jogadores.add(j1);
		jogadores.add(j2);
		jogadores.add(j3);
		jogadores.add(j4);
		
		Jogo j = new Jogo(jogadores);
		
		j.proximoJogador();
		
		j.cartaAmostra = new ComprarQuatro();
		
		//remove todas as cartas
		while (j.monteJogado.retirarCarta() != null) {}
		
		//remove todas as cartas
		while (j.monteDisponivel.retirarCarta() != null) {}
		
		Pular cd0 = new Pular(Cor.AZUL);
		Inverter cd1 = new Inverter(Cor.VERMELHO);
		
		j.monteDisponivel.adicionaCarta(cd0);
		j.monteDisponivel.adicionaCarta(cd1);
		
		CartaNumerica c0 = new CartaNumerica(Cor.VERMELHO, 3);
		CartaNumerica c1 = new CartaNumerica(Cor.AZUL, 9);
		CartaNumerica c2 = new CartaNumerica(Cor.VERDE, 6);
		CartaNumerica c3 = new CartaNumerica(Cor.AMARELO, 2);
		
		j.monteJogado.adicionaCarta(c0);
		j.monteJogado.adicionaCarta(c1);
		j.monteJogado.adicionaCarta(c2);
		j.monteJogado.adicionaCarta(c3);
		
		List <Carta> cartas = j.pegarCartasMonteDisponivel(1);
		Assert.assertEquals(1, j.monteDisponivel.getCartas().size());
		Assert.assertEquals(cd0, cartas.get(0));
		
		cartas = j.pegarCartasMonteDisponivel(1);
		Assert.assertEquals(0, j.monteDisponivel.getCartas().size());
		Assert.assertEquals(cd1, cartas.get(0));
		
		/*for (Carta c : monteDisponivelPadraoTeste()) {
			j.monteDisponivel.getCartas().add(c);
		}*/
		
		//monte disponivel apenas com 2 cartas
		j.monteDisponivel.adicionaCarta(cd0);
		j.monteDisponivel.adicionaCarta(cd1);
		
		//retirada de 3 cartas
		cartas = j.pegarCartasMonteDisponivel(3);
		Assert.assertEquals(3, cartas.size());
		
		//consequencia: quando o monte disponivel n�o possui a quantidade de cartas a ser retirada,
		//as cartas do monteJogado s�o embaralhadas e passa a formar
		//o novo monte disponivel. Dessa forma a terceira carta pode ser retirada
		Assert.assertEquals(cd0, cartas.get(0));
		Assert.assertEquals(cd1, cartas.get(1));
		
		//como consequencia, o monteJogado passa a ficar vazio
		Assert.assertEquals(0, j.monteJogado.getCartas().size());
		//e o monteDisponivel passa a ter a quantidade do monteJogado (anterior) menos a quantidade cartas
		//faltante do pegarCartas.
		//Nesse caso, no inicio o monteDisponivel tem 2 cartas, mas quero pegar 3, 
		//então as 2 são retiradas, um novo monte é feito, e a mais uma carta é pega.
		Assert.assertEquals(3, j.monteDisponivel.getCartas().size());
		
		
	}
	
	@Test
	public void testeDisponibilizarNovoMonte() {
		
		List<Jogador> jogadores = new ArrayList<>();
		jogadores.add(new Jogador());
		jogadores.add(new Jogador());
		jogadores.add(new Jogador());
		
		Jogo j = new Jogo(jogadores);
		
		j.monteDisponivel = new Baralho(Baralho.VAZIO);
		j.monteJogado = new Baralho(Baralho.VAZIO);
		
		CartaNumerica c0 = new CartaNumerica(Cor.VERMELHO, 3);
		CartaNumerica c1 = new CartaNumerica(Cor.AZUL, 9);
		CartaNumerica c2 = new CartaNumerica(Cor.VERDE, 6);
		CartaNumerica c3 = new CartaNumerica(Cor.AMARELO, 2);
		
		j.monteJogado.adicionaCarta(c0);
		j.monteJogado.adicionaCarta(c1);
		j.monteJogado.adicionaCarta(c2);
		j.monteJogado.adicionaCarta(c3);
		
		Assert.assertEquals(4, j.monteJogado.quantidadeCartas());
		Assert.assertEquals(0, j.monteDisponivel.quantidadeCartas());
		j.disponibilizarNovoMonte();
		Assert.assertEquals(4, j.monteDisponivel.quantidadeCartas());
		Assert.assertEquals(0, j.monteJogado.quantidadeCartas());
		
	}
	
	@Test
	public void testeJogadaEhValida() {
		
	}
	
	
	
}
